"""
补充下载法律状态与同族专利
"""
import json
import warnings

import facade
from pymongo.errors import DuplicateKeyError
from xjlibrary.mdatetime.mtime import getDateTime

from base_sipo import BaseSipo


class DownLawAndPatcit(BaseSipo):
    def __init__(self):
        super().__init__()

        # 法律状态翻页
        self.urllaw = "http://pss-system.cnipa.gov.cn/sipopublicsearch/patentsearch/ui_searchLawState-showPage.shtml"
        self.headerlaw = {
            "Accept": "*/*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Host": "pss-system.gov.cn",
            "Origin": "http://pss-system.cnipa.gov.cn",
            "Proxy-Connection": "keep-alive",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
            "X-Requested-With": "XMLHttpRequest"
        }
        self.postdatelaw = {
            "lawState.nrdPn": "CN201089899Y",
            "lawState.nrdAn": "CN200720170285",
            "wee.bizlog.modulelevel": "0202201",
            "pagination.start": "0"
        }

        # 下载法律状态前需要请求
        self.lawhtml = "http://pss-system.cnipa.gov.cn/sipopublicsearch/search-ui/app/searchtools/dialog/law_state.jsp"
        self.headerlawhtml = {
            "Accept": "text/html, */*; q=0.01",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "Content-Length": "0",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Host": "pss-system.gov.cn",
            "Origin": "http://pss-system.cnipa.gov.cn",
            "Proxy-Connection": "keep-alive",
            "Referer": "http://pss-system.cnipa.gov.cn/sipopublicsearch/patentsearch/showViewList-jumpToView.shtml",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
            "X-Requested-With": "XMLHttpRequest"
        }

        # 下载引证文献的请求
        self.purl = "http://pss-system.cnipa.gov.cn/sipopublicsearch/patentsearch/showQuotationLitera-queryPatcitList.shtml"
        self.p_postdate = {
            "quotationQC.nrdAn": "CN201410107884",
            "quotationQC.nrdPn": "CN103826026A",
            "wee.bizlog.modulelevel": "0201702",
            "papagination.start": "0"
        }

        # 被引证
        self.cpurl = "http://pss-system.cnipa.gov.cn/sipopublicsearch/patentsearch/showQuotationLitera-queryCitLiteraForMultifunction.shtml"
        self.cp_postdate = {
            "quotationQC.nrdAn": "CN200710120662",
            "quotationQC.nrdPn": "CN100480621C",
            "wee.bizlog.modulelevel": "0202104",
            "citpagination.start": "0"
        }

        # 搜索的url
        self.searc_url = "http://pss-system.cnipa.gov.cn/sipopublicsearch/patentsearch/executeTableSearch0529-executeCommandSearch.shtml"
        self.search_data = {
            # 公开（公告）号=(CN+ OR HK+ OR MO+ OR TW+) AND 公开（公告）日=20181123 可能出现翻页无数据的情况
            "searchCondition.searchExp": "公开（公告）号=(CN+ OR HK+ OR MO+ OR TW+) AND 公开（公告）日=20181201",
            # "searchCondition.searchExp": '(公开（公告）日=20181123) AND 公开国家/地区/组织=(HK OR MO OR TW OR (发明类型=("I" OR "U" OR "D") AND 公开国家/地区/组织=(CN)))',
            "searchCondition.dbId": "VDB",
            "searchCondition.searchType": "Sino_foreign",
            "searchCondition.extendInfo['MODE']": "MODE_TABLE",
            "searchCondition.extendInfo['STRATEGY']": "STRATEGY_CALCULATE",
            "searchCondition.originalLanguage": "",
            "searchCondition.targetLanguage": "",
            "wee.bizlog.modulelevel": "0200201",
            "resultPagination.limit": "12"
        }

    def selectdb(self):
        """
        从mongodb获取需要下载的数据
        :return:
        """
        return self.db.patentinfo.find({"stat": 0}).limit(100)

    def get_down_count(self):
        """
        查看是否有需要下载的任务
        :return:
        """
        return self.db.patentinfo.count({"stat": 0})

    def down_search_page_1(self):
        """
        为防止搜索出来的数据为null
        :return:
        """
        self.logger.info("search one page get all pages")
        self.logger.info(self.search_data)
        BoolResult, errString, r = facade.BaseRequestPost(self.searc_url,
                                                          sn=self.sn,
                                                          proxies=self.proxys,
                                                          data=self.search_data,
                                                          endstring="",
                                                          mark="searchResultRecord",
                                                          allow_redirects=True,
                                                          headers=self.header3,
                                                          timeout=(30, 60))
        if BoolResult:
            self.logger.info("搜索成功")
            return True
        else:
            self.logger.info("搜索失败")
            self.logger.info(r.text)
            return False

    """
    ####################################################################################
    pmsg
    """

    def select_pmsg(self, requestid):
        rows = self.db.patentinfo.find_one({"requestsid": requestid}, {"pmsg": 1})
        return rows

    def down_patcit_page(self, i, pub_no, app_no, sn, proxys):
        """
        下载指定页的引证文献
        :param i:
        :param pub_no:
        :param app_no:
        :return:
        """
        start = i * 5
        self.p_postdate = {
            "quotationQC.nrdAn": app_no,
            "quotationQC.nrdPn": pub_no,
            "wee.bizlog.modulelevel": "0201702",
            "papagination.start": str(start)
        }
        return self.dow_patcit_page(sn, proxys)

    def dow_patcit_page(self, sn, proxys):
        self.header4 = {
            "Accept": "application/json, text/javascript, */*; q=0.01",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Origin": "http://pss-system.cnipa.gov.cn",
            "Referer": "http://pss-system.cnipa.gov.cn/sipopublicsearch/patentsearch/tableSearch-showTableSearchIndex.shtml",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
            "X-Requested-With": "XMLHttpRequest"
        }
        BoolResult, errString, r = facade.BaseRequestPost(self.purl,
                                                          sn=sn,
                                                          headers=self.header4,
                                                          endstring="",
                                                          data=self.p_postdate,
                                                          proxies=proxys,
                                                          mark="patcitList",
                                                          allow_redirects=True,
                                                          timeout=(30, 60))
        if BoolResult:
            self.logger.info("下载引证成功,等待验证数据正确性")
            return True, r
        else:
            self.logger.info("下载引证失败" + errString)
            return False, r

    """
    ####################################################################################
    law
    """

    def select_lawmsg(self, requestid):
        rows = self.db.patentinfo.find_one({"requestsid": requestid}, {"lawmsg": 1})
        return rows

    def down_law_star(self):
        """
        下载法律状态前
        :return:
        """
        BoolResult, errString, r = facade.BaseRequestPost(self.lawhtml,
                                                          sn=self.sn,
                                                          headers=self.headerlawhtml,
                                                          proxies=self.proxys,
                                                          allow_redirects=True,
                                                          mark="main-body1",
                                                          timeout=(30, 60))
        if BoolResult:
            self.logger.info("解决法律417问题")
            return True, r
        else:
            self.logger.info("解决法律417问题失败")
            return False, r

    def down_law_page(self, i, pub_no, app_no):
        start = i * 5
        self.postdatelaw = {
            "lawState.nrdPn": pub_no,
            "lawState.nrdAn": app_no,
            "wee.bizlog.modulelevel": "0202201",
            "pagination.start": str(start)
        }
        return self.dow_law_page()

    def dow_law_page(self):
        BoolResult, errString, r = facade.BaseRequestPost(self.urllaw,
                                                          sn=self.sn,
                                                          headers=self.headerlaw,
                                                          endstring="",
                                                          data=self.postdatelaw,
                                                          proxies=self.proxys,
                                                          mark="lawStateList",
                                                          allow_redirects=True,
                                                          timeout=(30, 60))
        if BoolResult:
            self.logger.info("下载法律成功")
            return True, r
        else:
            self.logger.info("下载法律失败" + errString)
            try:
                self.logger.info("respose的类容是:" + r.text)
            except:
                pass
            return False, r

    """
    ####################################################################################
    cp
    """

    def select_cpmsg(self, requestid):
        rows = self.db.patentinfo.find_one({"requestsid": requestid}, {"cpmsg": 1})
        return rows

    def down_cpatcit(self, i, pub_no, app_no):
        start = i * 5
        self.cp_postdate = {
            "quotationQC.nrdAn": app_no,
            "quotationQC.nrdPn": pub_no,
            "wee.bizlog.modulelevel": "0202104",
            "citpagination.start": start
        }
        return self.down_cpatcit_page()

    def down_cpatcit_page(self):
        """
        下载被引文献
        :return:
        """
        BoolResult, errString, r = facade.BaseRequestPost(self.cpurl,
                                                          sn=self.sn,
                                                          endstring="",
                                                          data=self.cp_postdate,
                                                          headers=self.header3,
                                                          proxies=self.proxys,
                                                          allow_redirects=True,
                                                          mark="citingpatList",
                                                          timeout=(30, 60))
        if BoolResult:
            self.logger.info("下载被引文献成功")
            return True, r
        else:
            self.logger.info("下载被引文献失败")
            return False, r

    """
    ####################################################################################
    """

    def set_dates_417(self, app_no, requestid):
        self.dates417["viewQC.viewLiteraQCList[0].srcCnName"] = "检索式:申请号=({}+)".format(app_no)
        self.dates417["viewQC.viewLiteraQCList[0].srcEnName"] = "SearchStatement:申请号=({}+)".format(app_no)
        self.dates417["viewQC.viewLiteraQCList[0].searchCondition.executableSearchExp"] = "VDB:(ID='{}')".format(
            requestid)
        searchKeywords = ""
        for assi in app_no:
            searchKeywords += "[%s][ ]{0,}" % assi
        searchKeywords += "[ ]{0,}"
        self.dates417["viewQC.searchKeywords[0]"] = searchKeywords

    def updatepatent(self, rid, dicts):
        lawmsg = json.dumps(dicts, ensure_ascii=False)
        try:
            self.db.patentinfo.update({"requestsid": rid}, {"$set": {"lawmsg": lawmsg}})
        except DuplicateKeyError as e:
            warnings.warn(str(e))

    def updatepatentpmsg(self, rid, dicts):
        pmsg = json.dumps(dicts, ensure_ascii=False)
        try:
            self.db.patentinfo.update({"requestsid": rid}, {"$set": {"pmsg": pmsg}})
        except DuplicateKeyError as e:
            warnings.warn(str(e))

    def updatepatentcpmsg(self, rid, dicts):
        cpmsg = json.dumps(dicts, ensure_ascii=False)
        try:
            self.db.patentinfo.update({"requestsid": rid}, {"$set": {"cpmsg": cpmsg}})
        except DuplicateKeyError as e:
            warnings.warn(str(e))

    def updatepatentstat(self, requestsid, stat, cpnum):
        self.db.patentinfo.update({"requestsid": requestsid},
                                  {"$set": {"stat": stat, "cpnum": cpnum, "downdate": getDateTime()}})

    def oneces(self, row, sn, proxys):
        """
        调用一次的流程
        :return:
        """
        # 该标志标志是否有请求发出 如果没有就没必要sleep
        self.down_stat = 0
        tcount = row["tcount"]
        pcount = row["pcount"]
        app_no = row["app_no"]
        pub_no = row["pub_no"]
        requestsid = row["requestsid"]
        # 数据库状态 默认唯一 如果下面的下载有一个没成功则为0
        stat = 1
        # 开始下载引证文献
        self.logger.info("pcount is:" + str(pcount))
        # 如果小于5就已经在下载里面了 没有翻页不需要下载
        if int(pcount) > 5:
            # 查询之前有没有下载一部分翻页的 下载的就不用下载
            rows = self.select_pmsg(requestsid)
            dictlist = []
            dicts = {}
            if rows["pmsg"] != "":
                dicts = json.loads(rows["pmsg"])
                dictlist = list(dicts.keys())
            # 这里的i代表页 如果页存在就不用下载
            for i in range(1, (int(pcount) - 1) // 5 + 1):
                if str(i + 1) in dictlist:
                    continue
                # 下载 指定页的引证文献
                self.down_stat = 1
                boolresult, r = self.down_patcit_page(i, pub_no, app_no, sn, proxys)
                if boolresult:
                    try:
                        # 有可能出现json loads失败的情况 该情况下无法不能算成功
                        if json.loads(r.text)["patcitList"] is None:
                            self.logger.info(self.p_postdate)
                            self.logger.info(r.text)
                            self.logger.info("验证引证失败" + requestsid)
                            return False, 1, "下载下来的数据为空"
                        else:
                            self.logger.info("验证数据正确")

                        dicts[str(i + 1)] = json.loads(r.text)
                        self.updatepatentpmsg(requestsid, dicts)
                    except json.decoder.JSONDecodeError as e:
                        self.logger.error(r.text)
                        self.down_search_page(sn, proxys)
                        return False, 1, "下载的数据不是json无法通过json解析"
                else:
                    try:
                        if r.status_code == 404:
                            return False, 2, "404错误"
                        else:
                            return False, 3, "下载引证文献错误"
                    except:
                        return False, 3, "下载引证文献错误"

        self.logger.info("stat is:" + str(stat))
        # time.sleep(2)
        self.logger.info("法律状态 tcount is:" + str(tcount))
        # 下载法律状态
        if int(tcount) > 5:
            # 下载页面 如果不下载页面 会出现417 问题
            results, r = self.down_law_star()
            if not results:
                return False, 4, "下载法律状态的前置状态失败"
            # 查看法律状态的已下载结果
            rows = self.select_lawmsg(requestsid)
            dictlist = []
            dicts = {}

            if rows["lawmsg"] != "":
                dicts = json.loads(rows["lawmsg"])
                dictlist = list(dicts.keys())
            # 循环页并跳过已下载的页
            for i in range(1, (int(tcount) - 1) // 5 + 1):
                if str(i + 1) in dictlist:
                    continue
                # 下载法律状态
                self.down_stat = 1
                boolresult, r = self.down_law_page(i, pub_no, app_no)
                if boolresult:
                    if json.loads(r.text)["lawStateList"] is None:
                        self.logger.info("请求的法律失败")
                        self.logger.info(requestsid)
                        return False, 5, "下载法律状态的信息为空"
                    dicts[str(i + 1)] = json.loads(r.text)
                    self.updatepatent(requestsid, dicts)
                else:
                    try:
                        if r.text.find("uilogin-forwardLogin") > -1:
                            return False, 6, "出现重新登录标志，请检查登录情况"
                    except:
                        return False, 7, "下载法律状态失败"

        self.logger.info("stat is:" + str(stat))
        # 查询被引证文献数量
        results = self.db.pageidjson.find_one({"requestsid": requestsid}, {"cpnum": 1})
        if not results:
            # 如果没有查到 说明数据库有数据缺失 设置-1状态码最后检查
            self.db.patentinfo.update({"requestsid": requestsid}, {"$set": {"stat": -1}})
            return False, 8, "数据有缺失请检查并补充"
        cpnum = int(results["cpnum"])
        self.logger.info("cpnum is:" + str(cpnum))
        # 检查被引数据是否需要下载
        if cpnum > 0:
            # 查询数据库已经下载了的情况
            rows = self.select_cpmsg(requestsid)
            dictlist = []
            dicts = {}
            if rows["cpmsg"] != "":
                dicts = json.loads(rows["cpmsg"])
                dictlist = list(dicts.keys())
            # 按页下载并跳过已经下载了的数据
            for i in range(1, (int(cpnum) - 1) // 5 + 2):
                if str(i) in dictlist:
                    continue
                self.down_stat = 1
                boolresult, r = self.down_cpatcit(i - 1, pub_no, app_no)
                if boolresult:
                    # 有可能出现json loads失败的情况 该情况下无法不能算成功
                    try:
                        if json.loads(r.text)["citingpatList"] is None:
                            self.logger.info(self.p_postdate)
                            self.logger.info(r.text)
                            self.logger.info("验证被引失败" + requestsid)
                            return False, 9, "下载的被引数据为null"
                        else:
                            self.logger.info("验证数据正确")

                        dicts[str(i)] = json.loads(r.text)
                        self.updatepatentcpmsg(requestsid, dicts)
                    except json.decoder.JSONDecodeError as e:
                        self.logger.info(e)
                        self.logger.info(r.text)
                        return False, 10, "下载被引数据错误，不是json,不能使用json解析"
                else:
                    try:
                        if r.status_code == 404:
                            return False, 11, "下载被引失败，404错误"
                        else:
                            return False, 12, "下载被引失败"
                    except:
                        return False, 13, "下载被引失败"

        self.logger.info("stat is %s" % stat)
        self.logger.info("requetsid is %s" % requestsid)
        self.updatepatentstat(requestsid, stat, cpnum)
        return True, True, "全部成功"


def printr(r):
    try:
        print(r.text)
    except:
        pass


"""
**********************多进程分布式代码**************************
"""
import time
from multiprocessing.managers import BaseManager


class QueueManager(BaseManager):
    pass


class NodeTask(object):
    def __init__(self):
        self.register()
        # 连接到服务器，也就是运行task_master.py的机器:
        self.server_addr = '192.168.30.123'
        print('Connect to server %s...' % self.server_addr)
        # 端口和验证码注意保持与task_master.py设置的完全一致:
        self.m = QueueManager(address=(self.server_addr, 5003), authkey=b'abc')
        self.task = None
        self.result = None

    def register(self):
        # 由于这个QueueManager只从网络上获取Queue，所以注册时只提供名字:
        QueueManager.register('get_task_queue')
        QueueManager.register('get_result_queue')

    def conn(self):
        # 从网络连接:
        self.m.connect()

    def set_task_result_obj(self):
        # 获取Queue的对象:
        self.task = self.m.get_task_queue()
        self.result = self.m.get_result_queue()


def task_distributed():
    node = NodeTask()
    node.conn()
    node.set_task_result_obj()
    down = DownLawAndPatcit()
    while True:
        boolresult, msg = down.set_cookie_from_db(updatetime="searchupdatetime")
        down.logger.info(msg)
        if not boolresult:
            if msg == "代理为空" or msg == "cookie表为空":
                time.sleep(20)
            elif isinstance(msg, int):
                time.sleep(msg)
            continue
        boolresult = down.down_search_page(down.sn, down.proxys)
        if not boolresult:
            down.logger.info("调用获取ip方法失败")
            continue
        num = 0
        while True:
            row = node.task.get()
            num += 1
            downbool, errnum, errmsg = down.oneces(row, down.sn, down.proxys)
            if not downbool:
                if errnum in (1, 9, 10):
                    down.logger.info("num is:" + str(num) + ";" + str(errnum) + ";" + errmsg + ";")
                    down.down_search_page(down.sn, down.proxys)
                    boolresult = down.down_search_page_1()
                if errnum in (2, 11):
                    down.logger.info("num is:" + str(num) + ";" + str(errnum) + ";" + errmsg + ";")
                    down.down_search_page(down.sn, down.proxys)
                if errnum in (3, 4, 5, 6, 7, 12, 13):
                    # 这个错误是单纯需要新的cookie
                    down.logger.info("num is:" + str(num) + ";" + str(errnum) + ";" + errmsg + ";")
                    break
                if errnum == 8:
                    # 数据有缺失 属于需要检查的
                    down.logger.info("num is:" + str(num) + ";" + str(errnum) + ";" + errmsg + ";")
                    break
                time.sleep(5)

            else:
                if down.down_stat == 1:
                    time.sleep(10)


if __name__ == "__main__":
    task_distributed()
